/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.mes.service.impl;

import com.xy.biz.base.client.*;
import com.xy.biz.base.domain.constant.DictCodeConstant;
import com.xy.biz.base.domain.req.GetBizCodeRequest;
import com.xy.biz.base.domain.req.GetUnitConvertRequest;
import com.xy.biz.base.domain.req.ListBomRequest;
import com.xy.biz.base.domain.req.ListDictItemRequest;
import com.xy.biz.base.domain.resp.*;
import com.xy.biz.mc.client.MessagePushClient;
import com.xy.biz.mc.domain.Message;
import com.xy.biz.mc.domain.consts.MessageTypeConstant;
import com.xy.biz.mc.domain.req.MessagePushRequest;
import com.xy.biz.mes.domain.bo.*;
import com.xy.biz.mes.domain.converter.ManufactureResultConverter;
import com.xy.biz.mes.domain.enums.*;
import com.xy.biz.mes.domain.query.*;
import com.xy.biz.mes.domain.req.HandOverGoodsRequest;
import com.xy.biz.mes.domain.req.HandOverRequest;
import com.xy.biz.mes.domain.resp.GetManufactureResultResponse;
import com.xy.biz.mes.domain.resp.GetManufactureTaskCodeResponse;
import com.xy.biz.mes.listener.ManufactureTaskListener;
import com.xy.biz.mes.manager.ManufactureOrderManager;
import com.xy.biz.mes.manager.ManufactureResultManager;
import com.xy.biz.mes.manager.ManufactureTaskManager;
import com.xy.biz.mes.service.ManufactureTaskService;
import com.xy.lang.domain.Result;
import com.xy.lang.enums.HandOverResultEnum;
import com.xy.lang.enums.OccupyStatusEnum;
import com.xy.lang.exception.ObjectNotFoundException;
import com.xy.lang.util.ResultUtils;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.gid.service.GidService;
import com.xy.tool.json.JsonUtils;
import com.xy.tool.util.BeanUtilsEx;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *
 *
 * @author zsp
 * @date 2022-1-6
 */
@Slf4j
@Service
public class ManufactureTaskServiceImpl implements ManufactureTaskService {

    @Autowired
    private GidService gidService;
    @Autowired
    private BomClient bomClient;
    @Autowired
    private DictClient dictClient;
    @Autowired
    private BizCodeClient bizCodeClient;
    @Autowired
    private EquipmentClient equipmentClient;
    @Autowired
    private MessagePushClient messagePushClient;
    @Autowired
    private UnitConvertClient unitConvertClient;
    @Autowired
    private ManufactureTaskManager manufactureTaskManager;
    @Autowired
    private ManufactureOrderManager manufactureOrderManager;
    @Autowired
    private ManufactureResultManager manufactureResultManager;

    private CopyOnWriteArrayList<ManufactureTaskListener> listeners = new CopyOnWriteArrayList<>();

    @Override
    public void addListener(ManufactureTaskListener listener) {
        if (listener != null) {
            listeners.add(listener);
        }
    }

    @Override
    public void removeListener(ManufactureTaskListener listener) {
        if (listener != null) {
            listeners.remove(listener);
        }
    }

    private void fireSaveInspectionResult(Collection<GetManufactureResultResponse> collection) {
        for (ManufactureTaskListener listener : listeners) {
            listener.onSave(collection);
        }
    }

    @Override
    public Result<?> saveAllManufactureTask(Collection<ManufactureTaskBO> collection) {
        Set<Long> manufactureOrderIdSet = new HashSet<>();
        collection.forEach(e -> manufactureOrderIdSet.add(e.getManufactureOrderId()));

        List<ManufactureTaskBO> manufactureTaskBOList = manufactureTaskManager.listManufactureTask(ManufactureTaskQuery.max()
                .manufactureOrderIdList(new ArrayList<>(manufactureOrderIdSet))
                .withGoodsFlag(true)
                .build().addStatus(ManufactureTaskStatusEnum.PENDING_MANUFACTURE.getCode())
                .addStatus(ManufactureTaskStatusEnum.MANUFACTURING.getCode())
                .addStatus(ManufactureTaskStatusEnum.RECORDED.getCode())
                .addStatus(ManufactureTaskStatusEnum.REVIEWED.getCode()));
        if (!CollectionUtils.isEmpty(manufactureTaskBOList)) {
            Set<Long> existingOrderGoodsIdsSet = manufactureTaskBOList.stream()
                    .filter(e -> !CollectionUtils.isEmpty(e.getGoodsList()))
                    .flatMap(e -> e.getGoodsList().stream())
                    .filter(e -> Objects.equals(ManufactureGoodsTypeEnum.PRODUCTION.getCode(), e.getType()))
                    .map(ManufactureTaskGoodsBO::getManufactureOrderGoodsId)
                    .collect(Collectors.toSet());
            if (!CollectionUtils.isEmpty(existingOrderGoodsIdsSet)) {
                Set<Long> orderGoodsIdSet = collection.stream()
                        .filter(e -> !CollectionUtils.isEmpty(e.getGoodsList()))
                        .flatMap(e -> e.getGoodsList().stream())
                        .map(ManufactureTaskGoodsBO::getManufactureOrderGoodsId)
                        .collect(Collectors.toSet());
                if (orderGoodsIdSet.removeAll(existingOrderGoodsIdsSet)) {
                    return Result.ofBadRequest("此通知单已分配！");
                }
            }
        }

        List<ManufactureOrderBO> manufactureOrderList
                = manufactureOrderManager.listManufactureOrderById(manufactureOrderIdSet, true);
        if (CollectionUtils.isEmpty(manufactureOrderList)
                || !Objects.equals(manufactureOrderIdSet.size(), manufactureOrderList.size())) {
            return Result.ofBadRequest("不存在的生产订单：" + manufactureOrderIdSet);
        }
        Set<Long> productGoodsIdSet = new HashSet<>();
        manufactureOrderList.forEach(order -> order.getGoodsList().forEach(goods -> {
            if (Objects.equals(order.getOrderType(), ManufactureOrderTypeEnum.MANUFACTURE.getCode())) {
                productGoodsIdSet.add(goods.getGoodsId());
            }
        }));
        BomWrapper bomWrapper = new BomWrapper();
        if (!CollectionUtils.isEmpty(productGoodsIdSet)) {
            Result<List<GetBomResponse>> listResult = bomClient.listBom(ListBomRequest.builder()
                    .goodsIdList(new ArrayList<>(productGoodsIdSet))
                    .withEquipment(true)
                    .withGoods(true).build());
            List<GetBomResponse> bomList = ResultUtils.getOrException(listResult);
            if (CollectionUtils.isEmpty(bomList)) {
                return Result.ofNotFound("此产品下不存在物料清单：" + productGoodsIdSet + "，请先创建物料清单！");
            }
            if (!Objects.equals(productGoodsIdSet.size(), bomList.size())) {
                productGoodsIdSet.removeAll(bomList.stream().map(GetBomResponse::getGoodsId).collect(Collectors.toSet()));
                return Result.ofNotFound("此产品下不存在物料清单：" + productGoodsIdSet + "，请先创建物料清单！");
            }
            bomList.forEach(e -> {
                bomWrapper.bomGoodsMap.put(e.getGoodsId(), e.getGoodsList());
                bomWrapper.bomUnitMap.put(e.getGoodsId(), e.getUnit());
                bomWrapper.bomEquipmentMap.put(e.getGoodsId(), e.getEquipmentList());
            });
        }
        Map<Long, ManufactureOrderBO> manufactureOrderMap
                = manufactureOrderList.stream().collect(
                Collectors.toMap(ManufactureOrderBO::getManufactureOrderId, e -> e));
        LocalDateTime now = LocalDateTime.now();
        GetBizCodeRequest getBizCodeRequest = GetBizCodeRequest.builder().code("MT").build();
        collection.forEach(task -> {
            task.setManufactureTaskId(gidService.generate());
            task.setManufactureTaskCode(ResultUtils.get(bizCodeClient.nextBizCode(getBizCodeRequest)));
            task.setStatus(ManufactureTaskStatusEnum.PENDING_MANUFACTURE.getCode());

            ManufactureOrderBO manufactureOrder = manufactureOrderMap.get(task.getManufactureOrderId());
            task.setManufactureOrder(manufactureOrder);
            manufactureOrder.setStatus(ManufactureOrderStatusEnum.ASSIGNED.getCode());
            manufactureOrder.setAssignUserId(UserContextHolder.getUserId());
            manufactureOrder.setAssignUserName(UserContextHolder.getUserName());
            manufactureOrder.setAssignTime(now);
            manufactureOrder.setUpdateTime(now);

            task.setManufactureOrderId(manufactureOrder.getManufactureOrderId());
            task.setManufactureOrderCode(manufactureOrder.getManufactureOrderCode());
            task.setOrderType(manufactureOrder.getOrderType());
            Map<Long, ManufactureOrderGoodsBO> manufactureOrderGoodsMap
                    = manufactureOrder.getGoodsList().stream().collect(
                    Collectors.toMap(ManufactureOrderGoodsBO::getManufactureOrderGoodsId, e -> e));
            task.getGoodsList().forEach(goods -> {
                ManufactureOrderGoodsBO manufactureOrderGoods = manufactureOrderGoodsMap.get(goods.getManufactureOrderGoodsId());
                BeanUtilsEx.copyProperties(manufactureOrderGoods, goods);
                goods.setManufactureTaskGoodsId(gidService.generate());
                goods.setManufactureTaskId(task.getManufactureTaskId());
                goods.setHandOverResult(HandOverResultEnum.UNDO.getCode());
                goods.setManufactureTaskCode(task.getManufactureTaskCode());
                goods.setCreateTime(LocalDateTime.now());
                goods.setUpdateTime(LocalDateTime.now());
                goods.setCheckFlag(false);
            });
            addMaterialGoodsAndEquipment(task, bomWrapper);
            task.setTenantId(UserContextHolder.getTenantId());
            task.setCreateUserId(UserContextHolder.getUserId());
            task.setCreateUserName(UserContextHolder.getUserName());
            task.setCreateTime(now);
            task.setUpdateTime(now);
        });
        int affectedRows = manufactureTaskManager.saveAllManufactureTask(collection);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    private void addMaterialGoodsAndEquipment(ManufactureTaskBO manufactureTaskBO, BomWrapper bomWrapper) {
        Map<Long, List<GetBomGoodsResponse>> bomGoodsMap = bomWrapper.getBomGoodsMap();
        Map<Long, List<GetBomEquipmentResponse>> bomEquipmentMap = bomWrapper.getBomEquipmentMap();
        Map<Long, String> bomUnitMap = bomWrapper.getBomUnitMap();
        if (Objects.equals(manufactureTaskBO.getOrderType(), ManufactureOrderTypeEnum.MANUFACTURE.getCode())) {
            List<ManufactureTaskGoodsBO> manufactureTaskGoodsBOList = new ArrayList<>();
            List<ManufactureTaskEquipmentBO> manufactureTaskEquipmentBOList = new ArrayList<>();
            manufactureTaskBO.getGoodsList().forEach(e -> {
                List<GetBomGoodsResponse> bomGoodsResponseList = bomGoodsMap.get(e.getGoodsId());
                List<GetBomEquipmentResponse> bomEquipmentResponseList = bomEquipmentMap.get(e.getGoodsId());
                String productUnit = bomUnitMap.get(e.getGoodsId());
                if (!CollectionUtils.isEmpty(bomGoodsResponseList)) {
                    bomGoodsResponseList.forEach(e1 -> {
                        ManufactureTaskGoodsBO manufactureTaskGoodsBO = BeanUtilsEx.copyProperties(e1, ManufactureTaskGoodsBO::new);
                        manufactureTaskGoodsBO.setManufactureTaskGoodsId(gidService.generate());
                        manufactureTaskGoodsBO.setManufactureTaskId(manufactureTaskBO.getManufactureTaskId());
                        manufactureTaskGoodsBO.setManufactureTaskCode(manufactureTaskBO.getManufactureTaskCode());
                        manufactureTaskGoodsBO.setManufactureOrderId(manufactureTaskBO.getManufactureOrderId());
                        manufactureTaskGoodsBO.setManufactureOrderCode(manufactureTaskBO.getManufactureOrderCode());
                        manufactureTaskGoodsBO.setUnit(e1.getUnit());
                        manufactureTaskGoodsBO.setCreateTime(LocalDateTime.now());
                        manufactureTaskGoodsBO.setUpdateTime(LocalDateTime.now());
                        manufactureTaskGoodsBO.setHandOverResult(HandOverResultEnum.UNDO.getCode());
                        manufactureTaskGoodsBO.setType(ManufactureGoodsTypeEnum.MATERIAL.getCode());
                        manufactureTaskGoodsBO.setTenantId(UserContextHolder.getTenantId());
                        try {
                            GetUnitConvertResponse unitConvert = ResultUtils.getOrException(
                                    unitConvertClient.getMultiplier(GetUnitConvertRequest.builder()
                                            .converteeUnit(productUnit)
                                            .converterUnit(e.getUnit())
                                            .build()));
                            if (unitConvert.isAsc()) {
                                manufactureTaskGoodsBO.setExpectQuantity(((e.getExpectQuantity() * e1.getCount())
                                        * unitConvert.getMultiplier()));
                                manufactureTaskGoodsBO.setBomUnit(((e1.getCount() * unitConvert.getMultiplier()) + " " + e1.getUnit() + "/" + e.getUnit()));
                            } else {
                                manufactureTaskGoodsBO.setExpectQuantity(((e.getExpectQuantity() * e1.getCount())
                                        / unitConvert.getMultiplier()));
                                manufactureTaskGoodsBO.setBomUnit(((e1.getCount() / unitConvert.getMultiplier()) + " " + e1.getUnit() + "/" + e.getUnit()));
                            }
                        } catch (ObjectNotFoundException | NullPointerException exception) {
                            manufactureTaskGoodsBO.setExpectQuantity(0.0);
                            log.error(exception.getMessage());
                        }
                        manufactureTaskGoodsBOList.add(manufactureTaskGoodsBO);
                    });
                }
                if (!CollectionUtils.isEmpty(bomEquipmentResponseList)) {
                    bomEquipmentResponseList.forEach(e2 -> {
                        ManufactureTaskEquipmentBO manufactureTaskEquipmentBO = BeanUtilsEx.copyProperties(e2, ManufactureTaskEquipmentBO::new);
                        manufactureTaskEquipmentBO.setManufactureTaskEquipmentId(gidService.generate());
                        manufactureTaskEquipmentBO.setManufactureTaskId(manufactureTaskBO.getManufactureTaskId());
                        manufactureTaskEquipmentBO.setManufactureTaskCode(manufactureTaskBO.getManufactureTaskCode());
                        manufactureTaskEquipmentBO.setUsage(0);
                        manufactureTaskEquipmentBO.setCheckFlag(false);
                        manufactureTaskEquipmentBOList.add(manufactureTaskEquipmentBO);
                    });
                }
            });
            manufactureTaskBO.addEquipment(manufactureTaskEquipmentBOList);
            manufactureTaskBO.addGoods(manufactureTaskGoodsBOList);
        }
    }

    @Data
    static class BomWrapper {
        private Map<Long, List<GetBomGoodsResponse>> bomGoodsMap = new HashMap<>();
        private Map<Long, String> bomUnitMap = new HashMap<>();
        private Map<Long, List<GetBomEquipmentResponse>> bomEquipmentMap = new HashMap<>();
    }

    @Override
    public Result<?> updateManufactureTask(ManufactureTaskBO manufactureTaskBO) {
        ManufactureTaskBO manufactureTask = manufactureTaskManager.getManufactureTask(ManufactureTaskByIdQuery.builder()
                .manufactureTaskId(manufactureTaskBO.getManufactureTaskId())
                .build());
        if (Objects.isNull(manufactureTask)) {
            return Result.ofNotFound(String.valueOf(manufactureTaskBO.getManufactureTaskId()));
        }
        if (!CollectionUtils.isEmpty(manufactureTaskBO.getGoodsList())) {
            manufactureTaskBO.getGoodsList().forEach(e -> e.setUpdateTime(LocalDateTime.now()));
        }
        ManufactureOrderBO manufactureOrder = manufactureOrderManager.getManufactureOrder(manufactureTask.getManufactureOrderId());
        if (Objects.isNull(manufactureOrder)
                || manufactureOrder.getStatus().equals(ManufactureOrderStatusEnum.CANCELED.getCode())) {
            return Result.ofBadRequest(manufactureTask.getManufactureOrderId() + "生产通知已取消，无法操作！");
        }
        manufactureTaskBO.setManufactureOrderId(manufactureOrder.getManufactureOrderId());
        buildUpdateData(manufactureTaskBO);
        int affectedRows = manufactureTaskManager.updateManufactureTask(manufactureTaskBO);
        if (affectedRows > 0) {
            if (Objects.equals(ManufactureTaskStatusEnum.RECORDED.getCode(), manufactureTaskBO.getStatus())) {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append("通知单【")
                        .append(manufactureTask.getManufactureOrderCode())
                        .append("】的任务：【")
                        .append(manufactureTask.getManufactureTaskCode())
                        .append("】已完成清点。");
                sendMessage(stringBuilder.toString(), Collections.singleton(manufactureTask.getCreateUserId()));
            }
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    private void buildUpdateData(ManufactureTaskBO manufactureTaskBO) {
        if (Objects.equals(ManufactureTaskStatusEnum.RECORDED.getCode(), manufactureTaskBO.getStatus())) {
            manufactureTaskBO.setManufactureUserId(UserContextHolder.getUserId());
            manufactureTaskBO.setManufactureUserName(UserContextHolder.getUserName());
            manufactureTaskBO.setRecordTime(LocalDateTime.now());
        } else if (Objects.equals(ManufactureTaskStatusEnum.REVIEWED.getCode(), manufactureTaskBO.getStatus())) {
            manufactureTaskBO.setReviewUserId(UserContextHolder.getUserId());
            manufactureTaskBO.setReviewUserName(UserContextHolder.getUserName());
            manufactureTaskBO.setReviewTime(LocalDateTime.now());
        }
        // TODO
//        else if (Objects.equals(ManufactureTaskStatusEnum.HAND_OVER.getCode(), manufactureTaskBO.getStatus())) {
//            manufactureTaskBO.setHandOverUserId(UserContextHolder.getUserId());
//            manufactureTaskBO.setHandOverUserName(UserContextHolder.getUserName());
//            manufactureTaskBO.setHandOverTime(LocalDateTime.now());
//        }
        manufactureTaskBO.setUpdateTime(LocalDateTime.now());
    }

    @Override
    public Result<?> deleteManufactureTask(Long manufactureTaskId) {
        ManufactureTaskBO manufactureTask = manufactureTaskManager.getManufactureTask(
                ManufactureTaskByIdQuery.builder()
                        .manufactureTaskId(manufactureTaskId)
                        .build());
        if (Objects.isNull(manufactureTask)) {
            return Result.ofNotFound(String.valueOf(manufactureTaskId));
        }
        int affectedRows = manufactureTaskManager.deleteManufactureTask(manufactureTaskId);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public ManufactureTaskBO getManufactureTask(ManufactureTaskByIdQuery query) {
        ManufactureTaskBO manufactureTask = manufactureTaskManager.getManufactureTask(query);
        if (query.getWithGoodsFlag() && !CollectionUtils.isEmpty(manufactureTask.getGoodsList())) {
            manufactureTask.getGoodsList().stream()
                    .map(e -> e.calculateAttritionRate(e))
                    .collect(Collectors.toList());
        }
        return manufactureTask;
    }

    @Override
    public List<ManufactureTaskBO> listManufactureTaskById(Collection<Long> collection) {
        return manufactureTaskManager.listManufactureTaskById(collection);
    }

    @Override
    public List<ManufactureTaskBO> listManufactureTask(ManufactureTaskQuery query) {
        return manufactureTaskManager.listManufactureTask(query);
    }

    @Override
    public List<GetManufactureTaskCodeResponse> listOwnerManufactureTaskCode(ManufactureTaskQuery query) {
        query.setManufactureUserId(UserContextHolder.getUserId());
        query.setWithEquipmentFlag(false);
        query.setWithGoodsFlag(false);
        query.setWithRecordFlag(false);
        List<ManufactureTaskBO> manufactureTaskBOList = listManufactureTask(query);
        if (CollectionUtils.isEmpty(manufactureTaskBOList)) {
            return Collections.emptyList();
        }
        manufactureTaskBOList.stream()
                .filter(e -> !CollectionUtils.isEmpty(e.getGoodsList()))
                .flatMap(e -> e.getGoodsList().stream())
                .map(e -> e.calculateAttritionRate(e))
                .collect(Collectors.toList());
        return BeanUtilsEx.copyPropertiesForNewList(manufactureTaskBOList, GetManufactureTaskCodeResponse::new);
    }

    /**
     * 交付
     * @param request
     */
    @Override
    public Result<?> handOverManufactureTask(HandOverRequest request) {
        List<HandOverGoodsRequest> collection = request.getHandOverGoodsList();
        if (CollectionUtils.isEmpty(collection)) {
            return Result.ofBadRequest();
        }
        Map<Long, Integer> manufactureTaskGoodsIdMap = collection.stream()
                .collect(Collectors.toMap(HandOverGoodsRequest::getManufactureTaskGoodsId, HandOverGoodsRequest::getHandOverResult, (e1, e2) -> e2));
        List<ManufactureTaskGoodsBO> manufactureTaskGoodsBOList = manufactureTaskManager.listManufactureTaskGoods(ManufactureTaskGoodsQuery.max()
                .manufactureTaskGoodsIdList(new ArrayList<>(manufactureTaskGoodsIdMap.keySet()))
                .type(ManufactureGoodsTypeEnum.PRODUCTION.getCode())
                .handOverResult(HandOverResultEnum.UNDO.getCode())
                .checkFlag(true)
                .build());
        if (CollectionUtils.isEmpty(manufactureTaskGoodsBOList)) {
            return Result.ofErrorData("未查询到相关明细！");
        }
        Set<Long> manufactureTaskIdSet = manufactureTaskGoodsBOList.stream()
                .map(ManufactureTaskGoodsBO::getManufactureTaskId)
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(manufactureTaskIdSet)) {
            return Result.ofBadRequest();
        }
        List<ManufactureTaskBO> manufactureTaskBOList =
                manufactureTaskManager.listManufactureTask(ManufactureTaskQuery.max()
                        .manufactureTaskIdList(new ArrayList<>(manufactureTaskIdSet))
                        .status(ManufactureTaskStatusEnum.REVIEWED.getCode())
                        .build());
        if (CollectionUtils.isEmpty(manufactureTaskBOList)) {
            return Result.ofNotFound("未查询到已复核的任务");
        }
        if (!Objects.equals(manufactureTaskBOList.size(), manufactureTaskIdSet.size())) {
            manufactureTaskIdSet.removeAll(manufactureTaskBOList.stream().map(ManufactureTaskBO::getManufactureTaskId).collect(Collectors.toSet()));
            return Result.ofNotFound("存在未复核的任务" + manufactureTaskIdSet);
        }
//
//        List<ManufactureResultGoodsBO> exisitingManufactureResultGoodsBOList =
//                manufactureResultManager.listManufactureResultGoods(ManufactureResultQuery.max()
//                        .manufactureTaskIdList(new ArrayList<>(manufactureTaskIdSet)).build());
//        if (!CollectionUtils.isEmpty(exisitingManufactureResultGoodsBOList)) {
//            return Result.ofBadRequest("存在已交付的任务：" +
//                    exisitingManufactureResultGoodsBOList.stream()
//                            .map(ManufactureResultGoodsBO::getManufactureTaskCode)
//                            .collect(Collectors.toSet()));
//        }

        Set<Long> manufactureOrderIdSet =
                manufactureTaskBOList.stream().map(ManufactureTaskBO::getManufactureOrderId).collect(Collectors.toSet());
        List<ManufactureOrderBO> manufactureOrderBOList = manufactureOrderManager.listManufactureOrder(ManufactureOrderQuery.max()
                .manufactureOrderIdList(new ArrayList<>(manufactureOrderIdSet))
                //.status(ManufactureOrderStatusEnum.FINISHED.getCode())
                .build());

        if (CollectionUtils.isEmpty(manufactureOrderBOList)) {
            return Result.ofNotFound("未查询到相关通知单：" + manufactureOrderIdSet);
        }
        if (manufactureOrderIdSet.size() != manufactureOrderBOList.size()) {
            manufactureOrderIdSet.removeAll(manufactureOrderBOList.stream()
                    .map(ManufactureOrderBO::getManufactureOrderId).collect(Collectors.toSet()));
            return Result.fail("未查询到相关通知单：" + manufactureOrderIdSet);
        }
        //List<ManufactureTaskGoodsBO> mergedManufactureTaskGoodsList = merge(manufactureTaskGoodsBOList);
        List<ManufactureResultGoodsBO> manufactureResultGoodsBOList = new ArrayList<>();
        manufactureTaskGoodsBOList.forEach(e -> {
            e.setHandOverResult(manufactureTaskGoodsIdMap.get(e.getManufactureTaskGoodsId()));
            e.setFromStatusSet(Stream.of(HandOverResultEnum.UNDO.getCode()).collect(Collectors.toSet()));
            ManufactureResultGoodsBO manufactureResultGoodsBO = BeanUtilsEx.copyProperties(e, ManufactureResultGoodsBO::new);
            manufactureResultGoodsBO.setHandOverResult(manufactureTaskGoodsIdMap.get(e.getManufactureTaskGoodsId()));
            manufactureResultGoodsBO.setManufactureTaskGoodsBO(e);
            manufactureResultGoodsBOList.add(manufactureResultGoodsBO);
        });
        List<ManufactureResultBO> manufactureResultBOList = group(request, manufactureResultGoodsBOList);
        build(manufactureResultBOList);
        int affectedRows = manufactureResultManager.saveAllManufactureResult(manufactureResultBOList);
        if (affectedRows > 0) {
            fireSaveInspectionResult(ManufactureResultConverter.toResponse(manufactureResultBOList));
            Set<Integer> handOverTypeSet = manufactureResultBOList.stream()
                    .map(ManufactureResultBO::getHandOverResult).collect(Collectors.toSet());
            Map<String, String> receiverCategoryMap = ResultUtils.getOrException(dictClient.listDictItem(ListDictItemRequest.builder()
                            .dictGroupCode(DictCodeConstant.RECEIVER_CATEGORY).build()))
                    .stream().collect(Collectors.toMap(ListDictItemResponse::getDictCode, ListDictItemResponse::getDictValue));
            handOverTypeSet.forEach(e -> {
                String dictCode = HandOverResultEnum.getDictCode(e);
                if (StringUtils.hasText(dictCode)) {
                    String userIdCollection = receiverCategoryMap.get(dictCode);
                    if (StringUtils.hasText(userIdCollection)) {
                        Set<Long> userIdSet = Arrays.stream(userIdCollection.split(","))
                                .map(Long::valueOf).collect(Collectors.toSet());
                        sendMessage("新的" + HandOverResultEnum.getHandOverName(e) + "待查看", userIdSet);
                    }
                }
            });
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    private List<ManufactureResultBO> group(HandOverRequest request, List<ManufactureResultGoodsBO> manufactureResultGoodsBOList) {
        Map<Integer, List<ManufactureResultGoodsBO>> groupByHandOverResult =
                manufactureResultGoodsBOList.stream().collect(Collectors.groupingBy(ManufactureResultGoodsBO::getHandOverResult));
        List<ManufactureResultBO> manufactureResultBOList = new ArrayList<>();
        groupByHandOverResult.forEach((k, v) -> {
            ManufactureResultBO manufactureResult = new ManufactureResultBO();
            manufactureResult.setMemo(request.getMemo());
            manufactureResult.setHandOverResult(k);
            manufactureResult.setManufactureResultGoodsList(groupByHandOverResult.get(k));
            manufactureResultBOList.add(manufactureResult);
        });
        return manufactureResultBOList;
    }

    private void build(Collection<ManufactureResultBO> collection) {
        collection.forEach(manufactureResultBO -> {
            GetBizCodeRequest getBizCodeRequest = GetBizCodeRequest.builder().code("MR").build();
            manufactureResultBO.setManufactureResultId(gidService.generate());
            manufactureResultBO.setManufactureResultCode(ResultUtils.get(bizCodeClient.nextBizCode(getBizCodeRequest)));
            manufactureResultBO.setCreateTime(LocalDateTime.now());
            manufactureResultBO.setStatus(0);
            manufactureResultBO.setCreateUserId(UserContextHolder.getUserId());
            manufactureResultBO.setCreateUserName(UserContextHolder.getUserName());
            manufactureResultBO.setTenantId(UserContextHolder.getTenantId());
            manufactureResultBO.setUpdateTime(LocalDateTime.now());
            manufactureResultBO.getManufactureResultGoodsList().forEach(e -> {
                e.setManufactureResultGoodsId(gidService.generate());
                e.setManufactureResultId(manufactureResultBO.getManufactureResultId());
                e.setManufactureResultCode(manufactureResultBO.getManufactureResultCode());
            });
        });
    }

    @Override
    public List<ManufactureTaskGoodsBO> listManufactureTaskGoods(ManufactureTaskGoodsQuery query) {
        return manufactureTaskManager.listManufactureTaskGoods(query);
    }

    @Override
    public int countManufactureTask(ManufactureTaskQuery query) {
        return manufactureTaskManager.countManufactureTask(query);
    }

    @Override
    public int countManufactureTaskGoods(ManufactureTaskGoodsQuery query) {
        return manufactureTaskManager.countManufactureTaskGoods(query);
    }

    @Override
    public Result<?> saveAllManufactureTaskRecord(ManufactureTaskBO manufactureTaskBO) {
        int affectedRows = 0;
        List<ManufactureTaskRecordBO> recordList = manufactureTaskBO.getRecordList();
        if (!CollectionUtils.isEmpty(recordList)) {
            Long manufactureTaskId = manufactureTaskBO.getManufactureTaskId();
            ManufactureTaskBO manufactureTask = manufactureTaskManager.getManufactureTask(
                    ManufactureTaskByIdQuery.builder()
                            .manufactureTaskId(manufactureTaskId)
                            .build());
            if (Objects.isNull(manufactureTask)) {
                return Result.ofNotFound(String.valueOf(manufactureTaskId));
            }
            if (Objects.isNull(manufactureTaskBO.getRecordTemplateId())) {
                return Result.ofNotFound("模板Id不能为空！");
            }
            List<ManufactureTaskRecordBO> updateManufactureTaskRecordList = manufactureTaskManager.listManufactureTaskRecord(
                    ManufactureTaskRecordQuery.max()
                            .manufactureTaskId(manufactureTaskId)
                            .build());
            if (!CollectionUtils.isEmpty(updateManufactureTaskRecordList)) {
                Map<String, ManufactureTaskRecordBO> saveManufactureTaskRecordMap = recordList.stream().collect(
                        Collectors.toMap(
                                e -> e.getManufactureTaskId() + "-" + e.getRecordTemplateItemId(),
                                e -> e));
                Set<Long> deleteManufactureTaskRecordIdSet = new HashSet<>();
                for (ManufactureTaskRecordBO e : updateManufactureTaskRecordList) {
                    String key = e.getManufactureTaskId() + "-" + e.getRecordTemplateItemId();
                    if (!saveManufactureTaskRecordMap.containsKey(key)) {
                        deleteManufactureTaskRecordIdSet.add(e.getManufactureTaskRecordId());
                    }
                    ManufactureTaskRecordBO removed = saveManufactureTaskRecordMap.remove(key);
                    if (removed != null) {
                        e.setContent(removed.getContent());
                        e.setMemo(removed.getMemo());
                    }
                }
                if (!CollectionUtils.isEmpty(saveManufactureTaskRecordMap)) {
                    saveManufactureTaskRecordMap.values().forEach(e -> {
                        e.setManufactureTaskId(manufactureTask.getManufactureTaskId());
                        e.setManufactureTaskCode(manufactureTask.getManufactureTaskCode());
                        e.setTenantId(UserContextHolder.getTenantId());
                    });
                    affectedRows = manufactureTaskManager.saveAllManufactureTaskRecord(saveManufactureTaskRecordMap.values());
                }
                if (!CollectionUtils.isEmpty(deleteManufactureTaskRecordIdSet)) {
                    manufactureTaskManager.deleteManufactureTaskRecord(deleteManufactureTaskRecordIdSet);
                }
                affectedRows += manufactureTaskManager.updateAllManufactureTaskRecord(updateManufactureTaskRecordList);
            } else {
                recordList.forEach(e -> {
                    e.setManufactureTaskId(manufactureTask.getManufactureTaskId());
                    e.setManufactureTaskCode(manufactureTask.getManufactureTaskCode());
                    e.setTenantId(UserContextHolder.getTenantId());
                });
                affectedRows = manufactureTaskManager.saveAllManufactureTaskRecord(recordList);
            }
            manufactureTaskBO.setManufactureOrderId(manufactureTask.getManufactureOrderId());
            manufactureTaskBO.setManufactureUserId(UserContextHolder.getUserId());
            manufactureTaskBO.setManufactureUserName(UserContextHolder.getUserName());
            manufactureTaskBO.setRecordTime(LocalDateTime.now());
            manufactureTaskManager.updateManufactureTask(manufactureTaskBO);
        }
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofConflict();
    }

    @Override
    public Result<?> saveAllManufactureTaskEquipment(ManufactureTaskBO manufactureTaskBO) {
        int affectedRows = 0;
        Long manufactureTaskId = manufactureTaskBO.getManufactureTaskId();
        ManufactureTaskBO manufactureTask = manufactureTaskManager.getManufactureTask(
                ManufactureTaskByIdQuery.builder()
                        .manufactureTaskId(manufactureTaskId)
                        .build());
        if (Objects.isNull(manufactureTask)) {
            return Result.ofNotFound(String.valueOf(manufactureTaskId));
        }
        List<ManufactureTaskEquipmentBO> equipmentList = manufactureTaskBO.getEquipmentList();
        if (CollectionUtils.isEmpty(equipmentList)) {
            return Result.ofBadRequest();
        }

        Set<Long> equipmentIdSet =
                equipmentList.stream().map(ManufactureTaskEquipmentBO::getEquipmentId).collect(Collectors.toSet());
        Result<List<GetEquipmentResponse>> listResult = equipmentClient.listEquipmentById(equipmentIdSet);
        if (!listResult.wasSuccess()) {
            return Result.fail(listResult.getMsg());
        }
        List<GetEquipmentResponse> equipmentResponseList = listResult.getData();
        if (CollectionUtils.isEmpty(equipmentResponseList)) {
            return Result.ofNotFound("未找到此设备" + equipmentIdSet);
        } else if (equipmentIdSet.size() != equipmentResponseList.size()) {
            equipmentIdSet.removeAll(equipmentResponseList.stream().map(GetEquipmentResponse::getEquipmentId).collect(Collectors.toSet()));
            return Result.ofNotFound("未找到此设备" + equipmentIdSet);
        }
        List<Long> occupiedEquipmentList = equipmentResponseList.stream()
                .filter(e -> Objects.isNull(e.getOccupyStatus()) ||
                        OccupyStatusEnum.USING.getCode() == e.getOccupyStatus())
                .map(GetEquipmentResponse::getEquipmentId).collect(Collectors.toList());
        List<ManufactureTaskEquipmentBO> updateManufactureTaskEquipmentBOList = manufactureTaskManager.listManufactureTaskEquipment(
                ManufactureTaskEquipmentQuery.max()
                        .manufactureTaskId(manufactureTaskId)
                        .build());
        occupiedEquipmentList.removeAll(
                updateManufactureTaskEquipmentBOList.stream()
                        .map(ManufactureTaskEquipmentBO::getEquipmentId)
                        .collect(Collectors.toList()));
        equipmentList.removeIf(e -> occupiedEquipmentList.contains(e.getEquipmentId()));

        Map<Long, GetEquipmentResponse> equipmentResponseMap =
                equipmentResponseList.stream().filter(e -> !occupiedEquipmentList.contains(e.getEquipmentId()))
                        .collect(Collectors.toMap(GetEquipmentResponse::getEquipmentId, e -> e));
        equipmentList.forEach(e -> {
            e.setManufactureTaskId(manufactureTask.getManufactureTaskId());
            e.setManufactureTaskCode(manufactureTaskBO.getManufactureTaskCode());
            e.setCheckFlag(false);
            GetEquipmentResponse getEquipmentResponse = equipmentResponseMap.get(e.getEquipmentId());
            Objects.requireNonNull(getEquipmentResponse);
            e.setExpirationDate(getEquipmentResponse.getExpirationDate());
            e.setSpecification(getEquipmentResponse.getSpecification());
            e.setTenantId(UserContextHolder.getTenantId());
            e.setEquipmentCode(getEquipmentResponse.getEquipmentCode());
            e.setEquipmentName(getEquipmentResponse.getEquipmentName());
        });
        if (!CollectionUtils.isEmpty(updateManufactureTaskEquipmentBOList)) {
            Map<String, ManufactureTaskEquipmentBO> saveManufactureTaskEquipmentMap = equipmentList.stream().collect(
                    Collectors.toMap(
                            e -> e.getManufactureTaskId() + "-" + e.getEquipmentId(),
                            e -> e));
            Set<Long> deleteManufactureTaskEquipmentIdSet = new HashSet<>();
            for (ManufactureTaskEquipmentBO e : updateManufactureTaskEquipmentBOList) {
                String key = e.getManufactureTaskId() + "-" + e.getEquipmentId();
                if (!saveManufactureTaskEquipmentMap.containsKey(key)) {
                    deleteManufactureTaskEquipmentIdSet.add(e.getManufactureTaskEquipmentId());
                }
                ManufactureTaskEquipmentBO removed = saveManufactureTaskEquipmentMap.remove(key);
                if (removed != null) {
                    e.setUsage(removed.getUsage());
                }
            }
            if (!CollectionUtils.isEmpty(saveManufactureTaskEquipmentMap)) {
                saveManufactureTaskEquipmentMap.values().forEach(e -> {
                    e.setManufactureTaskId(manufactureTask.getManufactureTaskId());
                    e.setManufactureTaskCode(manufactureTask.getManufactureTaskCode());
                    e.setTenantId(UserContextHolder.getTenantId());
                });
                affectedRows = manufactureTaskManager.saveAllManufactureTaskEquipment(saveManufactureTaskEquipmentMap.values());
            }
            if (!CollectionUtils.isEmpty(deleteManufactureTaskEquipmentIdSet)) {
                manufactureTaskManager.deleteManufactureTaskRecord(deleteManufactureTaskEquipmentIdSet);
            }
            affectedRows += manufactureTaskManager.updateAllManufactureTaskEquipment(updateManufactureTaskEquipmentBOList);
        } else {
            equipmentList.forEach(e -> {
                e.setManufactureTaskId(manufactureTask.getManufactureTaskId());
                e.setManufactureTaskCode(manufactureTask.getManufactureTaskCode());
                e.setTenantId(UserContextHolder.getTenantId());
            });
            affectedRows = manufactureTaskManager.saveAllManufactureTaskEquipment(equipmentList);
        }
        if (!CollectionUtils.isEmpty(occupiedEquipmentList)) {
            return Result.ofConflict("选择的仪器中存在被占用仪器！" + occupiedEquipmentList + " 除被占用仪器外其余已添加。");
        }
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> saveAllManufactureTaskGoods(ManufactureTaskBO manufactureTaskBO) {
        if (CollectionUtils.isEmpty(manufactureTaskBO.getGoodsList())) {
            return Result.ofBadRequest();
        }
        List<ManufactureOrderBO> manufactureOrderList
                = manufactureOrderManager.listManufactureOrderById(Collections.singletonList(manufactureTaskBO.getManufactureOrderId()), true);
        if (CollectionUtils.isEmpty(manufactureOrderList)) {
            return Result.ofNotFound("输入了不存在的通知单号：" + manufactureTaskBO.getManufactureOrderId());
        }
        ManufactureTaskBO manufactureTask = manufactureTaskManager.getManufactureTask(
                ManufactureTaskByIdQuery.builder()
                        .manufactureTaskId(manufactureTaskBO.getManufactureTaskId())
                        .build());
        if (Objects.isNull(manufactureTask)) {
            return Result.ofNotFound(String.valueOf(manufactureTaskBO.getManufactureTaskId()));
        }
        Map<Long, ManufactureOrderGoodsBO> manufactureOrderGoodsMap
                = manufactureOrderList.get(0).getGoodsList().stream().collect(
                Collectors.toMap(ManufactureOrderGoodsBO::getManufactureOrderGoodsId, e -> e));
        if (CollectionUtils.isEmpty(manufactureOrderGoodsMap)) {
            return Result.ofNotFound("通知单物料/产品数据丢失！");
        }
        List<ManufactureTaskGoodsBO> goodsList = new ArrayList<>();
        Set<Long> orderGoodsIdSet = new HashSet<>();
        manufactureTaskBO.getGoodsList().forEach(goods -> {
            ManufactureOrderGoodsBO manufactureOrderGoods = manufactureOrderGoodsMap.get(goods.getManufactureOrderGoodsId());
            ManufactureTaskGoodsBO manufactureTaskGoodsBO = BeanUtilsEx.copyProperties(manufactureOrderGoods, ManufactureTaskGoodsBO::new);
            boolean addFlag = orderGoodsIdSet.add(manufactureOrderGoods.getManufactureOrderGoodsId());
            if (!addFlag) {
                manufactureTaskGoodsBO.setManufactureOrderGoodsId(gidService.generate());
            }
            manufactureTaskGoodsBO.setManufactureTaskGoodsId(gidService.generate());
            manufactureTaskGoodsBO.setManufactureTaskId(manufactureTaskBO.getManufactureTaskId());
            manufactureTaskGoodsBO.setManufactureTaskCode(manufactureTaskBO.getManufactureTaskCode());
            manufactureTaskGoodsBO.setExpectCount(goods.getExpectCount());
            manufactureTaskGoodsBO.setSpecification(goods.getSpecification());
            manufactureTaskGoodsBO.setExpectQuantity(goods.getExpectQuantity());
            manufactureTaskGoodsBO.setCheckFlag(false);
            manufactureTaskGoodsBO.setCreateTime(LocalDateTime.now());
            manufactureTaskGoodsBO.setUpdateTime(LocalDateTime.now());
            goodsList.add(manufactureTaskGoodsBO);
        });
        int affectedRows = 0;
        Long manufactureTaskId = manufactureTaskBO.getManufactureTaskId();
        List<ManufactureTaskGoodsBO> updateManufactureTaskGoodsBOList =
                manufactureTaskManager.listManufactureTaskGoods(ManufactureTaskGoodsQuery.max()
                        .manufactureTaskId(manufactureTaskId).build());

        if (!CollectionUtils.isEmpty(updateManufactureTaskGoodsBOList)) {
            Map<Long, ManufactureTaskGoodsBO> saveManufactureTaskGoodsMap = goodsList.stream().collect(
                    Collectors.toMap(
                            ManufactureTaskGoodsBO::getManufactureOrderGoodsId,
                            e -> e));
            Set<Long> deleteManufactureTaskGoodsIdSet = new HashSet<>();
            for (ManufactureTaskGoodsBO e : updateManufactureTaskGoodsBOList) {
                Long key = e.getManufactureOrderGoodsId();
                if (!saveManufactureTaskGoodsMap.containsKey(key)) {
                    deleteManufactureTaskGoodsIdSet.add(e.getManufactureTaskGoodsId());
                }
                ManufactureTaskGoodsBO removed = saveManufactureTaskGoodsMap.remove(key);
                if (removed != null) {
                    e.setSpecification(removed.getSpecification());
                    e.setExpectCount(removed.getExpectCount());
                    e.setExpectQuantity(removed.getExpectQuantity());
                }
            }
            if (!CollectionUtils.isEmpty(saveManufactureTaskGoodsMap)) {
                saveManufactureTaskGoodsMap.values().forEach(e -> {
                    e.setManufactureTaskId(manufactureTask.getManufactureTaskId());
                    e.setManufactureTaskCode(manufactureTask.getManufactureTaskCode());
                    e.setTenantId(UserContextHolder.getTenantId());
                });
                affectedRows = manufactureTaskManager.saveAllManufactureTaskGoods(saveManufactureTaskGoodsMap.values());
            }
            if (!CollectionUtils.isEmpty(deleteManufactureTaskGoodsIdSet)) {
                manufactureTaskManager.deleteManufactureTaskGoods(deleteManufactureTaskGoodsIdSet);
            }
            affectedRows += manufactureTaskManager.updateAllManufactureTaskGoods(updateManufactureTaskGoodsBOList);
        } else {
            goodsList.forEach(e -> {
                e.setManufactureTaskId(manufactureTask.getManufactureTaskId());
                e.setManufactureTaskCode(manufactureTask.getManufactureTaskCode());
                e.setTenantId(UserContextHolder.getTenantId());
            });
            affectedRows = manufactureTaskManager.saveAllManufactureTaskGoods(goodsList);
        }
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    /**
     * 核查
     * @param manufactureTaskBO
     */
    @Override
    public Result<?> checkManufactureTask(ManufactureTaskBO manufactureTaskBO) {
        ManufactureTaskBO manufactureTask = manufactureTaskManager.getManufactureTask(
                ManufactureTaskByIdQuery.builder()
                        .manufactureTaskId(manufactureTaskBO.getManufactureTaskId())
                        .build());
        if (Objects.isNull(manufactureTask)) {
            return Result.ofNotFound(String.valueOf(manufactureTaskBO.getManufactureTaskId()));
        }
        ManufactureOrderBO manufactureOrder = manufactureOrderManager.getManufactureOrder(manufactureTask.getManufactureOrderId());
        if (Objects.isNull(manufactureOrder)
                || manufactureOrder.getStatus().equals(ManufactureOrderStatusEnum.CANCELED.getCode())) {
            return Result.ofBadRequest(manufactureTask.getManufactureOrderId() + "生产通知已取消，无法操作！");
        }
        manufactureTaskBO.setManufactureOrderId(manufactureOrder.getManufactureOrderId());
        int row = manufactureTaskManager.checkManufactureTask(manufactureTaskBO);
        if (row > 0) {
            return Result.success();
        }
        return Result.fail();
    }

    @Override
    public List<ManufactureTaskRecordBO> listManufactureTaskRecord(ManufactureTaskRecordQuery query) {
        return manufactureTaskManager.listManufactureTaskRecord(query);
    }

    private void sendMessage(String message, Set<Long> receiverIdSet) {
        if (CollectionUtils.isEmpty(receiverIdSet)) {
            return;
        }
        Message msg = Message.builder()
                //.type(0)
                .data(1)
                //.path(MessageTypeConstant.FLOW_LIST)
                .remark(message)
                .build();
        receiverIdSet.forEach(e -> messagePushClient.send(MessagePushRequest.builder()
                .data(JsonUtils.toJson(msg).getBytes())
                .dataType(0)
                .expiredSeconds(0L)
                .toId(e)
                .offlineFlag(true).build()));
    }

}
